from direct.task import Task 
from panda3d.core import *
from panda3d.physx import *
from random import randint, random

# Setup our physics world
class Physics():
    def __init__(self):
            # Scene
            self.oldT = 0
            sceneDesc = PhysxSceneDesc()
            sceneDesc.setGravity(Vec3(0, 0, -9.81))
            sceneDesc.setFlag(PhysxEnums.SFForceConeFriction, True)
            self.scene = PhysxManager.getGlobalPtr().createScene(sceneDesc)
            self.scene.enableControllerReporting(True) # <--
            self.scene.enableTriggerReporting(True)

            # Material
#            m0 = self.scene.getMaterial(0)
#            m0.setRestitution(0.2)
#            m0.setStaticFriction(0.3)
#            m0.setDynamicFriction(0.3)

            # Controller
            self.controllerNP = render.attachNewNode('Player')

            controllerDesc = PhysxCapsuleControllerDesc()
            controllerDesc.setHeight(1.0)
            controllerDesc.setRadius(0.5)
            controllerDesc.setStepOffset(0.6)
            controllerDesc.setSlopeLimit(70.0)

            self.controller = self.scene.createController(controllerDesc)
            self.controller.set_gravity(Vec3(0,0,1))
            self.controller.getActor().attachNodePath(self.controllerNP)
            self.controller.getActor().setName('Player')
            self.controller.getActor().setMass(10.0)
           # self.controller.setSharpness(0.001)
            #______________________
            # Debug renderer
            self.debugNP = render.attachNewNode(self.scene.getDebugGeomNode())
            self.debugNP.node().off()
            #triggers
            
    def LoadMapPhysics(self,map):
            mesh = PhysxMeshPool.loadTriangleMesh(Filename('maps/'+map+'/'+map+'.nxb'))
            if mesh:
                shapeDesc = PhysxTriangleMeshShapeDesc()
                shapeDesc.setMesh(mesh)
                actorDesc = PhysxActorDesc()
                actorDesc.setName('Terrain')
                actorDesc.addShape(shapeDesc)
                #actorDesc.setGlobalHpr(0,180,0)
                actorDesc.setGlobalPos(Point3(0, 0, 0))
                self.scene.createActor(actorDesc)
                for geomNP in base.terrain.findAllMatches('**/+GeomNode'):
                        geomNode = geomNP.node()
                        if "Ladder" in geomNode.getName():
                            min, max = geomNP.getTightBounds()
                            centre = (min+max) * 0.5
                            size = Vec3(max - min)/2
                            if size.getX() > size.getY():
                                size=Vec3(size.getX(),size.getY()*4,size.getZ())
                            else:
                                size=Vec3(size.getX()*4,size.getY(),size.getZ())
                            shapeDesc = PhysxBoxShapeDesc()
                            shapeDesc.setDimensions(size)
                            shapeDesc.setTrigger(True)
                            actorDesc = PhysxActorDesc()
                            actorDesc.setName("Ladder")
                            actorDesc.addShape(shapeDesc)
                            actorDesc.setGlobalPos(Point3(centre.getX(),-centre.getY(),-centre.getZ()))
                            self.boxActor = self.scene.createActor(actorDesc)
                        if "Water" in geomNode.getName():
                            print "water"
                            geomNP.hide()
                            #base.watermesh = geomNP
            else:
                print "Failed Map Collisions."

    def cleanup(self):
            self.boxNP.removeNode()
            self.debugNP.removeNode()
            self.controllerNP.removeNode()

            self.ignore('space')
            self.ignore('physx-controller-down')

            self.scene.release()

            render.ls()

    def Update(self,task):
            dt = globalClock.getFrameTime() - self.oldT
            self.scene.simulate(dt)
            self.scene.fetchResults()
            base.Player1.UpdatePlayers()
            self.oldT = globalClock.getFrameTime()
            return Task.cont
    def doJump(self):
            self.controller.startJump(14)
    def doRaycast(self,a,dir,length):
            ray = PhysxRay()
            ray.setOrigin(a)
            ray.setDirection(dir)
            ray.setLength(length)
            # Find the closest hit
            hit = self.scene.raycastClosestShape(ray)
            return hit

    def doDown(self, *args):
            print 'DOWN:', args

          #def doCrouch( self, flag ):
          #  _np = self.controllerNP.getChild( 0 )

          #  if flag:
          #    offset = -0.5

          #    _np.setScale( 0.4 * 0.5 )
          #    _np.setZ( _np, offset )
          #    self.controller.setHeight( 0.0 )

          #  else:
          #    offset = + 1.0

          #    _np.setScale( 0.4 * 1.0 )
          #    _np.setZ( _np, offset )

          #    self.controller.setHeight( 1.0 )

          #  pos = self.controller.getPos( ) + Vec3( 0, 0, offset )
          #  self.controller.setPos( pos )


